package org.dizena.common.trace.feign.handler;

import feign.FeignException;
import feign.Response;
import feign.codec.Decoder;
import org.dizena.common.base.enums.EnumHeaderKey;
import org.dizena.common.base.enums.EnumLogLevel;
import org.dizena.common.except.BusinessException;
import org.dizena.common.logger.bean.LogInfo;
import org.dizena.common.logger.bean.LogRpcEvent;
import org.dizena.common.utils.ReqUtil;
import org.dizena.common.utils.RpcUtil;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.ApplicationEventPublisher;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class FeignTraceDecoder implements Decoder {

    final ApplicationEventPublisher publisher;
    final SpringDecoder decoder;

    public FeignTraceDecoder(ApplicationEventPublisher publisher, SpringDecoder decoder) {
        this.publisher = publisher;
        this.decoder = decoder;
    }

    @Override
    public Object decode(Response response, Type type) throws FeignException {
        LogInfo logInfo = new LogInfo();
        logInfo.setTraceId(ReqUtil.getTrace());
        logInfo.setClientIp(ReqUtil.getAllHeaderMap().get(EnumHeaderKey.REQUEST_IP));
        logInfo.setResponseTime(System.currentTimeMillis());
        try (InputStream is = response.body().asInputStream()) {
            String resultStr = new String(is.readAllBytes(), Charset.defaultCharset());
            //log.info("feign response {} {}", type.getTypeName(), resultStr);
            resultStr = RpcUtil.wrapperResult(resultStr);
            //log.info("feign wrap response {} {}", type.getTypeName(), resultStr);
            //logger
            logInfo.setResponseBody(resultStr);
            //logInfo.setReqParams();
            publisher.publishEvent(new LogRpcEvent(this, logInfo, EnumLogLevel.INFO));
            return this.decoder.decode(response.toBuilder().body(resultStr, StandardCharsets.UTF_8).build(), type);
        } catch (Exception e) {

            logInfo.setException("Feign Decode Response Error");
            //logInfo.setReqParams();
            publisher.publishEvent(new LogRpcEvent(this, logInfo, EnumLogLevel.ERROR));
            throw new BusinessException("Feign Decode Response Error");
        }
    }


}
